/*********************************************
   CPA1 LAB6, delopgave 2
   
   Filnavn : "uart.c"

   Polled driver for Mega16's USART
   The prototypes is defined in the header "uart.h".
      
   STK500 setup :
   
   Header "RS232 spare" connedted to RXD/TXD :
   RXD = PORTD, bit0
   TXD = PORTD, bit1
   ( See STK500 User Guide pages 3-5 )

   CodeVisionAVR C Compiler
   Chip: ATMega16
   
   Henning Hargaard 12/10 2005
**********************************************/

#include <mega16.h>
#include "uart.h"  

// Bit addressable I/O
#define RXC  UCSRA.7
#define UDRE UCSRA.5
#define FE   UCSRA.4
#define DOR  UCSRA.3
#define PE   UCSRA.2

/*************************************************************************
InitUART() :
USART initilization.
        Asyncronous mode.
	RX and TX enabled.
	No interrupts enabled.
	Baud rate = Parameter.
	Number of Stop Bits = 1.
	Parity = Parameter (disabled, EVEN, ODD).
Parameters :
	BaudRate     : Wanted Baud Rate.
	XTALFrekvens : Actual uController clock frequency. 
	DataBit      : Wanted number of Data Bits (5-8).
	Paritet      : Wanted Parity (0=disabled, 1=even, 2=odd ).
	 
	If any of the parameters is out of limits, no initialization is done.	
*************************************************************************/
void InitUART( unsigned long BaudRate, unsigned long XTALFrekvens, unsigned char DataBit, unsigned char Paritet )
{
unsigned char ParityMask = 0;
unsigned int TempUBRR;

  // Only initializations, if parameters is within limits
  if ( (DataBit >= 5) && (DataBit <= 8) && (Paritet <= 2) )
  {	
    // "Normal" clock, no multiprocesser mode (default)
    UCSRA=0b00100000;
    // No interrupts enabled
    // Receiver enabled
    // Transmitter enabled
    // No 9 bit operation
    UCSRB=0b00011000;	
    // Setup the parity and number of Data Bits
    if ( Paritet == 1 )
      ParityMask = 0b00100000;
    else if ( Paritet == 2 )		
      ParityMask = 0b00110000;
    // Asynchronous operation, 1 stop bit
    // Bit7 always has to be 1
    UCSRC = 0b10000000 | ParityMask | ((DataBit-5)<<1) ;
    // Set Baud Rate according to the parameters XTALFrekvens and BaudRate :
    // Select Baud Rate (first store "UBRRH--UBRRL" in local 16-bit variable,
    //                   then write the two 8-bit registers seperately):
    TempUBRR = XTALFrekvens/16/BaudRate - 1;
    // ( Trick : Adding (BaudRate/2) before division results in correct rounding )
    // ( If you want correkt rounding, substitude the statement above with :
    // ( TempUBRR = (XTALFrekvens/16+(BaudRate/2))/BaudRate - 1; )
    // ( This can be omitted and still working! )
    // Baud Rate Register only has 12 valid bits.
    TempUBRR &= 0x0FFF;
    UBRRH = TempUBRR >> 8;
    UBRRL = TempUBRR & 0x00FF;
  }	
}

/*************************************************************************
CharReady() :
  Returns 0, if the UART has NOT received a new character.
  Returns value <> 0, if the UART HAS received a new character.
*************************************************************************/
unsigned char CharReady()
{
   return RXC;
}

/*************************************************************************
RecError() :
Controls the received characters for errors.
Returns :
	0 : No errors in received character, or if no character is received.
	1 : Frame error.
	2 : Overrun Error.
	3 : Parity Error.
*************************************************************************/
unsigned char RecError()
{
   if (FE)
   	return 1;
   if (DOR)
   	return 2;
   if (PE)
   	return 3;
   return 0;
}   

/*************************************************************************
ReadChar() :
Awaits new character received.
Then this character is returned.
*************************************************************************/
char ReadChar()
{
  // Wait for new character received
  while ( !RXC )
  {}                        
  // Then return it
  return UDR;
}

/*************************************************************************
SendChar() :
Awaits transmitter-register ready.
Then it send the character.
Parameter :
	Tegn : Character for sending. 
*************************************************************************/
void SendChar(char Tegn)
{
  // Wait for transmitter register empty (ready for new character)
  while ( !UDRE )
  {}
  // Then send the character
  UDR = Tegn;
}

/*************************************************************************
SendStringFlash() :
Sends 0-terminated string, stored in FLASH memory.
Parameter :
         *Streng : Pointer to the FLASH-string.
*************************************************************************/
void SendStringFlash(flash char* Streng)
{
  // Repeat until 0-terminator :
  while (*Streng)
  // Send character and then adjust the pointer
  SendChar(*Streng++);
}

/*************************************************************************
SendStringSRAM() :
Sends 0-terminated string, stored in SRAM memory.
Parameter :
         *Streng : Pointer to the SRAM-string.
*************************************************************************/
void SendStringSRAM(char* Streng)
{
  // Repeat until 0-terminator :
  while (*Streng)
  // Send character and then adjust the pointer
  SendChar(*Streng++);
}